﻿using System;
using System.Net.Sockets;
using System.Threading;
using NModbus;
using wcsServo.utils;

namespace wcsServo.client
{
    public class ModbusClient
    {
        private TcpClient _tcpClient;
        private IModbusMaster _master;
        private string _unitNo;
        private string _host;
        private int _port;
        private int _slot;
        private Action<string, string, string> _showMessage;

        public ModbusClient(string unitNo, string host, int port, int slot, Action<string, string, string> showMessage)
        {
            _unitNo = unitNo;
            _host = host;
            _port = port;
            _slot = slot;
            _showMessage = showMessage;
        }

        public void Start()
        {
            //创建TCP客户端
            try
            {
                Connect();
            }
            catch (Exception)
            {

            }
            finally
            {
                DisconnectCallback();
            }
        }

        private void Connect()
        {
            try
            {
                ShowMessage("0", $"尝试与设备[{_unitNo}]建立连接!IP[{_host}]:[{_port}]");
                _tcpClient = new TcpClient(_host, _port);//创建Modbus TCP客户端
                _master = new ModbusFactory().CreateMaster(_tcpClient);
                ShowMessage("0", $"与设备[{_unitNo}]连接成功!");
            }
            catch (Exception ex)
            {
                throw new Exception($"与设备[{_unitNo}]连接失败:{ex.Message}");
            }
        }

        public string ReadData(int addr, int count, string typ)
        {
            try
            {
                ushort[] src = _master.ReadHoldingRegisters((byte)_slot, (ushort)addr, (ushort)count);
                return MyHexUtils.GetString(src, typ);
            }
            catch (Exception ex)
            {
                throw new Exception("读取数据失败" + ex.Message);
            }
        }

        public void WriteData(int addr, ushort[] value)
        {
            try
            {
                _master.WriteMultipleRegisters((byte)_slot, (ushort)addr, value);
            }
            catch (Exception)
            {
                throw new Exception("写入数据失败");
            }
        }

        public bool HasStarted()
        {
            return _tcpClient != null && _tcpClient.Connected;
        }

        #region ===连接守护方法===
        public void DisconnectCallback()
        {
            ThreadPool.QueueUserWorkItem(_ =>
            {
                while (true)
                {
                    if (!HasStarted())
                    {
                        try
                        {
                            Connect();
                        }
                        catch (Exception)
                        {
                            ShowMessage("1", $"设备[{_unitNo}]重连失败!");
                        }
                    }
                    Thread.Sleep(10 * 1000);
                }
            });
        }
        #endregion

        private void ShowMessage(string code, string message)
        {
            _showMessage?.Invoke(_unitNo, code, message);
        }
    }
}
